#include <tinx/types.h>
#include <tinx/syscall.h>

u32 _syscall0(u32 nr)
{
    u32 retval;
    asm volatile(
        "int $0x80\n"
        : "=a"(retval)
        : "a"(nr));
    return retval;
}

u32 _syscall1(u32 nr, u32 arg1)
{
    u32 retval;
    asm volatile(
        "int $0x80\n"
        : "=a"(retval)
        : "a"(nr), "b"(arg1));
    return retval;
}

u32 _syscall2(u32 nr, u32 arg1, u32 arg2)
{
    u32 retval;
    asm volatile(
        "int $0x80\n"
        : "=a"(retval)
        : "a"(nr), "b"(arg1), "c"(arg2));
    return retval;
}

u32 _syscall3(u32 nr, u32 arg1, u32 arg2, u32 arg3)
{
    u32 retval;
    asm volatile(
        "int $0x80\n"
        : "=a"(retval)
        : "a"(nr), "b"(arg1), "c"(arg2), "d"(arg3));
    return retval;
}

u32 _syscall6(u32 nr, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5, u32 arg6)
{
    u32 retval;
    asm volatile(
        "pushl %%ebp\n"
        "movl %7, %%ebp\n"
        "int $0x80\n"
        "popl %%ebp\n"
        : "=a"(retval)
        : "a"(nr), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5), "m"(arg6));
    return retval;
}

// 用于测试
int test()
{
    return _syscall0(SYS_NR_TEST);
}

// 创建子进程
pid_t fork()
{
    return _syscall0(SYS_NR_FORK);
}

// 任务主动退出
void exit(int status)
{
    _syscall1(SYS_NR_EXIT, status);
}

// 等待子进程退出, 返回值存到 status
pid_t waitpid(pid_t pid, int *status, int options)
{
    return _syscall3(SYS_NR_WAITPID, pid, (u32)status, options);
}

void yield()
{
    _syscall0(SYS_NR_YIELD);
}

// 获得当前时间
time_t time()
{
    return _syscall0(SYS_NR_TIME);
}

// 写文件 count 个字节
int write(fd_t fd, char *buf, int count)
{
    return _syscall3(SYS_NR_WRITE, fd, (u32)buf, count);
}

// 读文件 count 个字节
int read(fd_t fd, char *buf, int count)
{
    return _syscall3(SYS_NR_READ, fd, (u32)buf, count);
}

int ioctl(fd_t fd, int cmd, int arg)
{
    return _syscall3(SYS_NR_IOCTL, fd, cmd, arg);
}

int mkdir(char *pathname, int mode)
{
    return _syscall2(SYS_NR_MKDIR, (u32)pathname, mode);
}

int rmdir(char *pathname)
{
    return _syscall1(SYS_NR_RMDIR, (u32)pathname);
}

int link(char *oldname, char *newname)
{
    return _syscall2(SYS_NR_LINK, (u32)oldname, (u32)newname);
}

int unlink(char *filename)
{
    return _syscall1(SYS_NR_UNLINK, (u32)filename);
}

fd_t open(char *filename, int flags, int mode)
{
    return _syscall3(SYS_NR_OPEN, (u32)filename, flags, mode);
}

int close(fd_t fd)
{
    return _syscall1(SYS_NR_CLOSE, fd);
}

fd_t creat(char *filename, int mode)
{
    return _syscall2(SYS_NR_CREAT, (u32)filename, mode);
}

int readdir(fd_t fd, void *entry, int count)
{
    return _syscall3(SYS_NR_READDIR, fd, (u32)entry, count);
}

int lseek(fd_t fd, int offset, int whence)
{
    return _syscall3(SYS_NR_LSEEK, fd, offset, whence);
}

int chdir(char *pathname)
{
    return _syscall1(SYS_NR_CHDIR, (u32)pathname);
}

int chroot(char *pathname)
{
    return _syscall1(SYS_NR_CHROOT, (u32)pathname);
}

int stat(char *pathname, stat_t *statbuf)
{
    return _syscall2(SYS_NR_STAT, (u32)pathname, (u32)statbuf);
}

int fstat(fd_t fd, stat_t *statbuf)
{
    return _syscall2(SYS_NR_FSTAT, fd, (u32)statbuf);
}

int mknod(char *filename, int mode, int dev)
{
    return _syscall3(SYS_NR_MKNOD, (u32)filename, mode, dev);
}

int symlink(char *oldname, char *newname)
{
    return _syscall2(SYS_NR_SYMLINK, (u32)oldname, (u32)newname);
}

int readlink(char *pathname, char *buf, int size)
{
    return _syscall3(SYS_NR_READLINK, (u32)pathname, (u32)buf, size);
}

int getdents(fd_t fd, void *entries, int count)
{
    return _syscall3(SYS_NR_GETDENTS, fd, (u32)entries, count);
}

// 创建管道
int pipe(fd_t pipefd[2])
{
    return _syscall1(SYS_NR_PIPE, (u32)pipefd);
}

int rename(char *oldname, char *newname)
{
    return _syscall2(SYS_NR_RENAME, (u32)oldname, (u32)newname);
}

int mount(char *devname, char *dirname, int flags)
{
    return _syscall3(SYS_NR_MOUNT, (u32)devname, (u32)dirname, flags);
}

int umount(char *target)
{
    return _syscall1(SYS_NR_UMOUNT, (u32)target);
}

int umask(int mask)
{
    return _syscall1(SYS_NR_UMASK, mask);
}

int dup2(fd_t oldfd, fd_t newfd)
{
    return _syscall2(SYS_NR_DUP2, oldfd, newfd);
}

int dup(fd_t fds)
{
    return _syscall1(SYS_NR_DUP, fds);
}

int brk(u32 newbrk)
{
    return _syscall1(SYS_NR_BRK, newbrk);
}

int execve(char *filename, char *argv[], char *envp[])
{
    return _syscall3(SYS_NR_EXECVE, (u32)filename, (u32)argv, (u32)envp);
}

int shutdown()
{
    return _syscall0(SYS_NR_SHUTDOWN);
}

int reboot()
{
    return _syscall0(SYS_NR_REBOOT);
}

void *mmap(void *addr, size_t length, int prot, int flags, int fd, int offset)
{
    return (void *)_syscall6(SYS_NR_MMAP, (u32)addr, length, prot, flags, fd, offset);
}

int munmap(void *addr, size_t length)
{
    return _syscall2(SYS_NR_MUNMAP, (u32)addr, length);
}

int set_thread_area(void *desc)
{
    return _syscall1(SYS_NR_SET_THREAD_AREA, (u32)desc);
}